#!/usr/bin/env python3
import sys

__all__ = ["nested", "catch_warnings", "examine_warnings"]


try:
  from contextlib import nested
except ImportError:
  from contextlib import contextmanager

  @contextmanager
  def nested(*managers):
    exits = []
    vars = []
    exc = (None, None, None)
    try:
      for mgr in managers:
        exit = mgr.__exit__
        enter = mgr.__enter__
        vars.append(enter())
        exits.append(exit)
      yield vars
    except:
      exc = sys.exc_info()
    finally:
      while exits:
        exit = exits.pop()
        try:
          if exit(*exc):
            exc = (None, None, None)
        except:
          exc = sys.exc_info()
      if exc != (None, None, None):
        raise exc[1]


# copied from Python 2.6
try:
  from warnings import catch_warnings
except ImportError:

  class catch_warnings(object):
    def __init__(self, record=False, module=None):
      self._record = record
      self._module = sys.modules["warnings"]
      self._entered = False

    def __repr__(self):
      args = []
      if self._record:
        args.append("record=True")
      name = type(self).__name__
      return f"{name}({', '.join(args)})"

    def __enter__(self):
      if self._entered:
        raise RuntimeError(f"Cannot enter {self!r} twice")
      self._entered = True
      self._filters = self._module.filters
      self._module.filters = self._filters[:]
      self._showwarning = self._module.showwarning
      if self._record:
        log = []

        def showwarning(*args, **kwargs):
          log.append(WarningMessage(*args, **kwargs))

        self._module.showwarning = showwarning
        return log
      else:
        return None

    def __exit__(self, *exc_info):
      if not self._entered:
        raise RuntimeError(f"Cannot exit {self!r} without entering first")
      self._module.filters = self._filters
      self._module.showwarning = self._showwarning

  class WarningMessage(object):
    _WARNING_DETAILS = ("message", "category", "filename", "lineno", "file", "line")

    def __init__(self, message, category, filename, lineno, file=None, line=None):
      local_values = locals()
      for attr in self._WARNING_DETAILS:
        setattr(self, attr, local_values[attr])
      self._category_name = None
      if category.__name__:
        self._category_name = category.__name__


def examine_warnings(func):
  def wrapper():
    with catch_warnings(record=True) as ws:
      func(ws)

  return wrapper
